/******************************************************************************
 * This module provides the interface definitions for usart use
 *
 *  Known issues: 
 *  Pin definitions are valid for most msp430 devices, not all.
 *  
 *
 *   Ratish J. Punnoose,
 *     Modified and adapted from code provided with mspgcc written by
 *     Copyright 2002, R O SoftWare
 * $Id: msp430_usart.h 192 2010-08-18 00:00:38Z rjpunno $
 *****************************************************************************/
#ifndef INC_MSP430_USART
#define INC_MSP430_USART

#include <msp430/cmn_header.h>
#include <timed_wait.h>

#define MSP430_USART_CONFIG
#  include "proj_config.h"
#undef  MSP430_USART_CONFIG



/** Configuration Options for usart.
 * By default support is enabled for both UARTs.
 */
#ifndef USART0_SUPPORT
#define USART0_SUPPORT    (1)           // non-zero to enable usart0 code
#endif

#ifndef USART1_SUPPORT
#define USART1_SUPPORT    (1)           // non-zero to enable usart1 code
#endif



/** Configuration Option TIMER for TimedPutch.  If this is defined the
 * TxCCR2 compare register is used. */

#ifndef MSP430_USART0_TIMER
#  define MSP430_USART0_TIMER A
#endif

#ifndef MSP430_USART1_TIMER
#  define MSP430_USART1_TIMER  A
#endif




///////////////////////////////////////////////////////////////////////////////
// use the following macros to determine the 'mode' parameter values
// for usartInit0() and usartInit1()
#define USART_NONE  (0) 
#define USART_EVEN  (PENA + PEV)
#define USART_ODD   (PENA)
#define USART_1STOP (0)
#define USART_2STOP (SPB)
#define USART_7IBIT  (0)
#define USART_8BIT  (CHAR)

// Definitions for typical USART 'mode' settings
#define USART_8N1   (uint8_t)(USART_8BIT + USART_NONE + USART_1STOP)
#define USART_7N1   (uint8_t)(USART_7BIT + USART_NONE + USART_1STOP)
#define USART_8N2   (uint8_t)(USART_8BIT + USART_NONE + USART_2STOP)
#define USART_7N2   (uint8_t)(USART_7BIT + USART_NONE + USART_2STOP)
#define USART_8E1   (uint8_t)(USART_8BIT + USART_EVEN + USART_1STOP)
#define USART_7E1   (uint8_t)(USART_7BIT + USART_EVEN + USART_1STOP)
#define USART_8E2   (uint8_t)(USART_8BIT + USART_EVEN + USART_2STOP)
#define USART_7E2   (uint8_t)(USART_7BIT + USART_EVEN + USART_2STOP)
#define USART_8O1   (uint8_t)(USART_8BIT + USART_ODD  + USART_1STOP)
#define USART_7O1   (uint8_t)(USART_7BIT + USART_ODD  + USART_1STOP)
#define USART_8O2   (uint8_t)(USART_8BIT + USART_ODD  + USART_2STOP)
#define USART_7O2   (uint8_t)(USART_7BIT + USART_ODD  + USART_2STOP)

// Definitions for SPI modes
#define SPI_MASTER_3PIN (uint8_t)( CHAR | SYNC | MM | BIT7)
#define SPI_SLAVE_3PIN  (uint8_t)( CHAR | SYNC | BIT7)

#define SPI_MASTER_4PIN (uint8_t)( CHAR | SYNC | MM)
#define SPI_SLAVE_4PIN  (uint8_t)( CHAR | SYNC )


/** Option to sync read/write before returning */
#define USART_OPTION_ASYNC        0x01

/** Option to tell usartXReadWrite to read/write in reverse */
#define USART_OPTION_REVERSE_RW   0x02


/* ============================================================
 *   Aliases
 * ------------------------------------------------------------*/
#ifndef SSEL_UCLKI
#  define SSEL_UCLKI     	0x00
#endif

#ifndef SSEL_ACLK
#  define SSEL_ACLK          	0x10
#endif

#ifndef SSEL_SMCLK
  #define SSEL_SMCLK        	0x20
#endif
/* ============================================================*/



#if USART0_SUPPORT

/** @brief usart initialization function
 *
 *    This function initializes the USART for async mode or sync mode
 *    (SPI)
 * @param baudDiv  the baudrate divisor - use USART0_BAUD_DIV macro
 * @param baudMod  baudrate modulation - use USART0_BAUD_MOD macro, 
 * @param mode     comm mode,
 * @param clockSrc Either SSEL_ACLK or SSEL_SMCLK. See Pg 13-23 of
 *    MSP430 family guide.  (Bits 4,5)
 *
 * Example: usart0Init(USART0_BAUD_DIV(9600,CLOCKRATE),
 * USART0_BAUD_MOD(9600), USART_8N1, SSEL_ACLK);
 * *********************************************************/
void usart0Init(uint16_t baudDiv, uint8_t baudMod, uint8_t mode,
		uint8_t clockSrc);

/** @brief Stop usart function
 *
 * This function stops the use of the USART */
void usart0Close(void);


/** @brief Put a character into the USART output queue for
 * transmission.
 * @param ch  character to be transmitted
 *****************************************************************************/
void usart0Putch(unsigned char ch);

/** @brief Put a character into the USART output queue for
 * transmission.
 * @param ch  character to be transmitted
 * @param target_time time at which to be transmitted.
 *****************************************************************************/
void usart0TimedPutch(unsigned char ch, uint16_t target_time);


/** @brief Write a block of memory to the USART output
 *  This can be easily achieved by using usart0Putch, in a loop.
 *  However, a write is provided for greater efficiency.  Note that
 *  the write may not be fully completed upon return by this function.
 *  Use usart0TxIdle() to check if the transmission is completed
 *  before making any changes to the memory provided in src. 
 * @param txinfo  Pointer to buffer with information to transmit
 * @param bytes   Number of bytes to exchange
 * @param options   USART_OPTION_ASYNC  to return after initiating
 * write.  May not be complete*/
void usart0WriteWithOptions(unsigned char const *src, uint16_t bytes, uint16_t options);

/** @brief Write a block of memory to the USART output
 *  This can be easily achieved by using usart0Putch, in a loop.
 *  However, a write is provided for greater efficiency.  Note that
 *  the write may not be fully completed upon return by this function.
 *  Use usart0TxIdle() to check if the transmission is completed
 *  before making any changes to the memory provided in src. */
void usart0Write(unsigned char const *src, uint16_t bytes);

/** @brief Read a block of bytes from USART input to memory
 *  This can be easily achieved by using usart0Getch, in a loop.
 *  However, a block read is provided for greater efficiency.  */
void usart0Read(unsigned char *rx_buf, uint16_t bytes);


/** @brief Simultaneous (interleaved) read and write
 * This is primarily useful in SPI mode to send and receive data
 * simultaneously 
 * @param txinfo  Pointer to buffer with information to transmit
 * @param rxinfo  Pointer to reception ebuffer 
 * @param bytes   Number of bytes to exchange
 * @param options Combination of:  USART_OPTION_REVERSE_RW
 *                USART_OPTION_ASYNC */
void usart0ReadWrite(unsigned char const *txinfo,   
		     unsigned char *rxinfo,
		     uint16_t bytes, uint16_t options);
		     

/** @brief Returns the status of the USART transmit data
 *    registers.
 * @return   TRUE - if  the tx holding register is empty
 *    FALSE -  the tx holding  register is not empty
 *****************************************************************************/
int usart0TxIdle(void);

/** @brief Has the USART completed all pending transfers
 * @return   TRUE - if both the tx holding & shift registers are empty.
 *    FALSE - either the tx holding or shift register is not empty
 *****************************************************************************/
int usart0TxReady(void);




/** @brief Rremoves all characters from the USART transmit queue
 *    (without transmitting them).
 * @return void
 *****************************************************************************/
void usart0TxFlush(void);

/** @brief Get a character from the USART receive queue
 * 
 *  This function blocks until a character is received.  If non blocking is desired 
 *  then check to see if a character is available to receive  before reading
 *  @return   character 
 *****************************************************************************/
uint8_t usart0Getch(void);


/** @brief Flush all characters from the USART receive queue
 *  @return void */
void usart0RxFlush(void);

/** @brief USART Rx status
 * @return -1 if error, 0 if no error and empty, 1 if no error and
 * character available. */
int usart0RxStatus(void);

/** @brief Is the uart ready to receive
 * @return   TRUE, FALSE 
 *****************************************************************************/
int usart0RxReady(void);


#ifndef USART0_IDLEWAIT_TMETHOD
#define USART0_IDLEWAIT_TIMEOUT 0
#define USART0_IDLEWAIT_TMETHOD TNULL
#endif

#ifndef USART0_RW_DMARXCHANBUSY_TMETHOD
#define USART0_RW_DMARXCHANBUSY_TIMEOUT 0
#define USART0_RW_DMARXCHANBUSY_TMETHOD TNULL
#endif


#ifndef USART0_RW_DMATXCHANBUSY_TMETHOD
#define USART0_RW_DMATXCHANBUSY_TIMEOUT 0
#define USART0_RW_DMATXCHANBUSY_TMETHOD TNULL
#endif


#ifndef USART0_GETCH_TMETHOD
#define USART0_GETCH_TIMEOUT 0
#define USART0_GETCH_TMETHOD TNULL
#endif


#endif


#if USART1_SUPPORT
void usart1Init(uint16_t baudDiv, uint8_t baudMod, uint8_t mode,
		uint8_t clockSrc);
void usart1Close(void);
void usart1Putch(unsigned char ch);
void usart1TimedPutch(unsigned char ch, uint16_t target_time);
void usart1Write(unsigned char const *src, uint16_t bytes);
void usart1Read(unsigned char *rx_buf, uint16_t bytes);
int usart1TxIdle(void);
int usart1TxReady(void);
void usart1TxFlush(void);
uint8_t usart1Getch(void);
void usart1RxFlush(void);
int usart1RxStatus(void);
int usart1RxReady(void);
void usart1ReadWrite(unsigned char const *txinfo, 
		     unsigned char  *rxinfo, 
		     uint16_t bytes, uint16_t options);


#ifndef USART1_IDLEWAIT_TMETHOD
#define USART1_IDLEWAIT_TIMEOUT 0
#define USART1_IDLEWAIT_TMETHOD TNULL
#endif

#ifndef USART1_RW_DMARXCHANBUSY_TMETHOD
#define USART1_RW_DMARXCHANBUSY_TIMEOUT 0
#define USART1_RW_DMARXCHANBUSY_TMETHOD TNULL
#endif


#ifndef USART1_RW_DMATXCHANBUSY_TMETHOD
#define USART1_RW_DMATXCHANBUSY_TIMEOUT 0
#define USART1_RW_DMATXCHANBUSY_TMETHOD TNULL
#endif


#ifndef USART1_GETCH_TMETHOD
#define USART1_GETCH_TIMEOUT 0
#define USART1_GETCH_TMETHOD TNULL
#endif



#endif




/** Port mapping for USART, SPI, I2C.
 * Checked data sheet for on 16x, 12x, 13x1, 23x0, 22x2, 22x4
 *
 * Different pin allocation for 430xG461x, 430FG43x, 430FE42x
 *                              2.5 RxD, 2.4  for UART0
 *                              3.0, 3.1, 3.2 for SPI0, 
 *                              4.6, 4.7, for UART1
 *                              7.1, 7.1, 7.2 for SPI1
 *
 * 
 *  For MSP430C33x parts,
 *       P4.2,4.3, 4.4  SPI 
 *       P4.6, 4.7   UART mode
 * Alternate function enablement pins and port direction pins
 * */
#define UART0_PORTSEL		P3SEL
#define UART0_PORTINIT		(BIT4 | BIT5)

#define SPI0_PORTSEL		P3SEL
#define SPI0_PORTINIT		(BIT1 | BIT2 | BIT3)
#define SPI0_STE_PIN		BIT0


#define UART1_PORTSEL		P3SEL
#define UART1_PORTINIT		(BIT6 | BIT7)

#define SPI1_PORTSEL		P5SEL
#define SPI1_PORTINIT		(BIT1 | BIT2 | BIT3)
#define SPI1_STE_PIN		BIT0






/* use the following macros to determine the 'baudDiv' and 'baudMod'
 * parameter values for usartInit() 
 * CAUTION - 'baud' SHOULD ALWAYS BE A CONSTANT or
 * a lot of code will be generated. */

/**  @param baud Baudrate as an integer constant.
 *   @param BCLOCK Clock speed for the baud generator **/
#define USART_BAUD_DIV(baud, BCLOCK) (uint16_t)(BCLOCK / (baud))

// the following are used to calculate the UMOD values at compile time
#define CMOD(baud, BCLOCK)  ((BCLOCK / (baud)) - USART_BAUD_DIV(baud, BCLOCK))
#define M0(baud, BCLOCK)    (CMOD(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define M1(baud, BCLOCK)    (M0(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define M2(baud, BCLOCK)      (M1(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define M3(baud, BCLOCK)      (M2(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define M4(baud, BCLOCK)      (M3(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define M5(baud, BCLOCK)      (M4(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define M6(baud, BCLOCK)      (M5(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define M7(baud, BCLOCK)      (M6(baud, BCLOCK) + CMOD(baud, BCLOCK))
#define C0(baud, BCLOCK)      (uint8_t)((int)M0(baud, BCLOCK) ? BIT0 : 0)
#define C1(baud, BCLOCK)      (uint8_t)(((int)M1(baud, BCLOCK) - (int)M0(baud, BCLOCK)) ? BIT1 : 0)
#define C2(baud, BCLOCK)      (uint8_t)(((int)M2(baud, BCLOCK) - (int)M1(baud, BCLOCK)) ? BIT2 : 0)
#define C3(baud, BCLOCK)      (uint8_t)(((int)M3(baud, BCLOCK) - (int)M2(baud, BCLOCK)) ? BIT3 : 0)
#define C4(baud, BCLOCK)      (uint8_t)(((int)M4(baud, BCLOCK) - (int)M3(baud, BCLOCK)) ? BIT4 : 0)
#define C5(baud, BCLOCK)      (uint8_t)(((int)M5(baud, BCLOCK) - (int)M4(baud, BCLOCK)) ? BIT5 : 0)
#define C6(baud, BCLOCK)      (uint8_t)(((int)M6(baud, BCLOCK) - (int)M5(baud, BCLOCK)) ? BIT6 : 0)
#define C7(baud, BCLOCK)      (uint8_t)(((int)M7(baud, BCLOCK) - (int)M6(baud, BCLOCK)) ? BIT7 : 0)

/*lint -emacro(506,USART_BAUD_MOD) Conditional evaluations with constant */
/**  @param baud Baudrate as an integer constant.
 *   @param BCLOCK Clock speed for the baud generator **/
#define USART_BAUD_MOD(baud, BCLOCK) \
(uint8_t)\
(C7(baud, BCLOCK) +  C6(baud, BCLOCK) + C5(baud, BCLOCK) + \
 C4(baud, BCLOCK) +  C3(baud, BCLOCK) + C2(baud, BCLOCK) + \
 C1(baud, BCLOCK) +  C0(baud, BCLOCK))







#endif
